#include "extraPwm.h"
#include "cpu.h"
#include "stm32f4xx_hal_tim.h"
#include "xmzTypeDefine.h"

#define TIM_CLK_FREQ 2000000 // TIM1分频后时钟频率（168/84MHz）

PWM_CONF pwm_conf_list[2] = {{.pwm_pto = 0,
                              /*PWM */

                              .time_base     = 1,     // us
                              .pulse_width   = 500,   // 千分比 50%
                              .cycle_time    = 20000, // 20ms
                              .start_pulse_w = 500,   // 50%

                              /*PTO*/
                              .total_pulses  = 0,
                              .current_pulse = 0,
                              .current_freq  = 0.0f,
                              .V_min         = 0.0f,
                              .V_max         = 0.0f,
                              .accel         = 0.0f,
                              .accel_step    = 0.0f,
                              .decel_step    = 0.0f,
                              .state         = 0,
                              .pto_run_type  = 0,
                              /*通用参数 */
                              .is_active = 0, // 初始化不启动
                              .TIMx      = TIM8,
                              .htim      = {0},
                              .GPIO_Port = GPIOC,
                              .GPIO_Pin  = GPIO_PIN_6,
                              .GPIO_AF   = (uint8_t) GPIO_AF3_TIM8,
                              .TIMx_IRQn = TIM8_UP_TIM13_IRQn},
                             {.pwm_pto       = 0,
                              .time_base     = 1,     // us
                              .pulse_width   = 500,   // 千分比 50%
                              .cycle_time    = 20000, // 20ms
                              .start_pulse_w = 500,   // 50%
                              /*PTO*/
                              .total_pulses  = 0,
                              .current_pulse = 0,
                              .current_freq  = 0.0f,
                              .V_min         = 0.0f,
                              .V_max         = 0.0f,
                              .accel         = 0.0f,
                              .accel_step    = 0.0f,
                              .decel_step    = 0.0f,
                              .state         = 0,
                              .pto_run_type  = 0,
                              /*通用参数 */
                              .is_active = 0, // 初始化不启动
                              .TIMx      = TIM1,
                              .htim      = {0},
                              .GPIO_Port = GPIOE,
                              .GPIO_Pin  = GPIO_PIN_9,
                              .GPIO_AF   = (uint8_t) GPIO_AF1_TIM1,
                              .TIMx_IRQn = TIM1_UP_TIM10_IRQn}};

/**
 * @brief PWM初始化
 *
 * @param conf
 */
static void PWM_Init(PWM_CONF* conf) {
  if(conf->is_active == 0)
    return; // 未启用该通道
  // 1. 启用时钟
  if(conf->TIMx == TIM1)
    __HAL_RCC_TIM1_CLK_ENABLE();
  else if(conf->TIMx == TIM8)
    __HAL_RCC_TIM8_CLK_ENABLE();

  if(conf->GPIO_Port == GPIOC)
    __HAL_RCC_GPIOC_CLK_ENABLE();
  else if(conf->GPIO_Port == GPIOE)
    __HAL_RCC_GPIOE_CLK_ENABLE();

  // 2. 配置GPIO
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  GPIO_InitStruct.Pin              = conf->GPIO_Pin;
  GPIO_InitStruct.Mode             = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull             = GPIO_NOPULL;
  GPIO_InitStruct.Speed            = GPIO_SPEED_FREQ_HIGH;
  GPIO_InitStruct.Alternate        = conf->GPIO_AF;
  HAL_GPIO_Init(conf->GPIO_Port, &GPIO_InitStruct);

  // 2. 计算ARR（周期计数值，单位0.5us）
  uint32_t arr        = (conf->cycle_time * 2) - 1; // cycle_time单位为微秒
  conf->htim.Instance = conf->TIMx;
  // 1. 固定预分频，计数频率2MHz
  conf->htim.Init.Prescaler   = 84 - 1; // 168MHz / 84 = 2 MHz
  conf->htim.Init.CounterMode = TIM_COUNTERMODE_UP;
  /*pwm和pto有区别*/
  switch(conf->pwm_pto) {
    case TYPE_PWM_OUTPUT:
      conf->htim.Init.Period = arr;
      break;
    case TYPE_PTO_OUTPUT:
      conf->htim.Init.Period = 999; // 固定，反正后期是变动的
      break;
    default:
      Error_Handler();
      break;
  }
  conf->htim.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  if(HAL_TIM_PWM_Init(&conf->htim) != HAL_OK) {
    Error_Handler();
  }
  // 4. PWM通道配置
  TIM_OC_InitTypeDef sConfigOC = {0};
  sConfigOC.OCMode             = TIM_OCMODE_PWM1;
  switch(conf->pwm_pto) {
    case TYPE_PWM_OUTPUT: {
      // 脉冲宽度自动适配百分比/千分比/万分比
      if(conf->pulse_width <= 100)
        sConfigOC.Pulse = (conf->start_pulse_w * (arr + 1)) / 100;
      else if(conf->pulse_width <= 1000)
        sConfigOC.Pulse = (conf->start_pulse_w * (arr + 1)) / 1000;
      else
        sConfigOC.Pulse = (conf->start_pulse_w * (arr + 1)) / 10000;
    } break;
    case TYPE_PTO_OUTPUT: {
      sConfigOC.Pulse = 500; // 固定住
    } break;
    default:
      Error_Handler();
      break;
  }
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if(HAL_TIM_PWM_ConfigChannel(&conf->htim, &sConfigOC, TIM_CHANNEL_1) != HAL_OK) {
    Error_Handler();
  }

  // pto专有定时器更新中断计数
  if(conf->pwm_pto == TYPE_PTO_OUTPUT) {
    __HAL_TIM_ENABLE_IT(&conf->htim, TIM_IT_UPDATE);
    HAL_NVIC_SetPriority(conf->TIMx_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(conf->TIMx_IRQn);
  }
}

/**
 * @brief 初始化开启的pwm
 *
 */
void PWM_Init_all(void) {
  for(uint8_t i = 0; i < 2; i++) {
    PWM_Init(&pwm_conf_list[i]);
  }
}

static void PWM_Start(enum PWM_CH ch) {
  HAL_TIM_PWM_Start(&pwm_conf_list[ch].htim, TIM_CHANNEL_1);
  if(pwm_conf_list[ch].pwm_pto == TYPE_PTO_OUTPUT)
    __HAL_TIM_ENABLE(&pwm_conf_list[ch].htim);
}
static void PWM_Stop(enum PWM_CH ch) {
  if(pwm_conf_list[ch].pwm_pto == TYPE_PTO_OUTPUT)
    __HAL_TIM_DISABLE(&pwm_conf_list[ch].htim);
  HAL_TIM_PWM_Stop(&pwm_conf_list[ch].htim, TIM_CHANNEL_1);
}

/**
 * @brief 开启pwm配置
 *
 * @param ch 通道号
 * @param time_base 1:us
 * @param pulse_width 脉冲宽度 100 1000 100000
 * @param cycle_time 周期时间，循环时间
 * @param start_pulse_w 开始脉冲宽度
 */
void PWM_ON(enum PWM_CH ch, uint8_t time_base, uint16_t pulse_width, uint32_t cycle_time, uint16_t start_pulse_w) {
  PWM_CONF* pwm_conf = &pwm_conf_list[ch];
  if(pwm_conf->pwm_pto != 0x00) { // 该通道已被启用
    return;
  }
  pwm_conf->pwm_pto       = TYPE_PWM_OUTPUT;
  pwm_conf->time_base     = time_base;
  pwm_conf->pulse_width   = pulse_width;
  pwm_conf->cycle_time    = cycle_time;
  pwm_conf->start_pulse_w = start_pulse_w;
  pwm_conf->is_active     = 1;
}
Bool CTRL_PWM(Bool en, CTRL_PWM_S* instance) {
  if(en == false || instance == NULL)
    return False;
  // TODO 如果硬件发生变化，此处需要修改
  if(instance->pwm != 0 && instance->pwm != 1) {
    instance->status = PWM_STATUS_ERR_CH_NUM;
    return false;
  }
  if(pwm_conf_list[instance->pwm].is_active == 0) {
    instance->status = PWM_STATUS_ERR_NOT_ON;
    return false;
  }
  if(instance->enable == true)
    PWM_Start(instance->pwm);
  else
    PWM_Stop(instance->pwm);
  instance->status = PWM_STATUS_NOERROR;
  return True;
}
/**
 * @brief 通过频率（Hz）和占空比（%）设置PWM，单位固定微秒
 * @param ch PWM通道枚举
 * @param freq_hz 频率，单位Hz
 * @param duty_percent 占空比，百分比 0~100
 * @param pulse_width_unit 脉冲宽度单位基数，比如100代表百分比，1000代表千分比
 */
void PWM_SetByFreqDuty(enum PWM_CH ch, float freq_hz, float duty_percent, uint16_t pulse_width_unit) {
  uint8_t  time_base = 1; // 固定微秒单位
  uint32_t cycle_time;
  uint16_t start_pulse_w;

  // 计算周期时间，单位微秒
  float period_s = 1.0f / freq_hz;
  cycle_time     = (uint32_t) (period_s * 1e6f + 0.5f); // 秒转微秒，四舍五入

  // 计算开始脉冲宽度（以pulse_width_unit为基数的单位）
  start_pulse_w = (uint16_t) ((duty_percent / 100.0f) * pulse_width_unit + 0.5f);

  // 调用原配置函数
  PWM_ON(ch, time_base, pulse_width_unit, cycle_time, start_pulse_w);
}

// eg:PWM_SetByFreqDuty(PWM_CH1, 2000, 50.0f, 100);

/**
 * @brief PTO定时器中断处理函数，参考张宾的pwm_output.c
 *
 * @param ch PWM_CH 通道号
 */
static void PTO_IRQHandler(enum PWM_CH ch) {
  PWM_CONF* conf = &pwm_conf_list[ch];
  if(__HAL_TIM_GET_FLAG(&conf->htim, TIM_FLAG_UPDATE)) {
    __HAL_TIM_CLEAR_FLAG(&conf->htim, TIM_FLAG_UPDATE);
  }
  conf->current_pulse++;
  if(conf->current_pulse >= conf->total_pulses) { // 频率达到最大频率
    PWM_Stop(ch);
    return;
  }
  if(conf->pto_run_type == 0) {
    // 加速逻辑
    switch(conf->state) {
      case 0: { // 加速阶段
        conf->current_freq += conf->accel_step * 0.01f;
        if(conf->current_freq >= conf->V_max) {
          conf->current_freq = conf->V_max;
          conf->state        = 1; // 匀速阶段
        }
        break;
      }
      case 1: { // 匀速阶段
        // 判断是否需要开始减速
        uint32_t remaining_pulses = conf->total_pulses - conf->current_pulse;
        float    decel_pulses     = (conf->V_max * conf->V_max - conf->V_min * conf->V_min) / (2 * conf->decel_step);
        if(remaining_pulses <= decel_pulses) {
          conf->state = 2; // 减速阶段
        }
        break;
      }
      case 2: { // 减速阶段
        conf->current_freq -= conf->decel_step * 0.01f;
        if(conf->current_freq < conf->V_min) {
          conf->current_freq = conf->V_min;
        }
        break;
      }
    }
  }

  // 更新ARR和CCR
  uint32_t arr = (TIM_CLK_FREQ / conf->current_freq) - 1;
  __HAL_TIM_SET_AUTORELOAD(&conf->htim, arr);
  __HAL_TIM_SET_COMPARE(&conf->htim, TIM_CHANNEL_1, arr / 2);
}

// TIM1更新中断处理函数
void TIM1_UP_TIM10_IRQHandler(void) {
  PTO_IRQHandler(PWM_CH_2);
}

// TIM8更新中断处理函数
void TIM8_UP_TIM13_IRQHandler(void) {
  PTO_IRQHandler(PWM_CH_1);
}
void PTO_ON(enum PWM_CH ch) {
  PWM_CONF* conf = &pwm_conf_list[ch];
  if(conf->pwm_pto != 0x00 || conf->is_active != 0) { // 该通道已被启用
    return;
  }
  conf->pwm_pto   = TYPE_PTO_OUTPUT;
  conf->is_active = 1;
}
Bool CTRL_PTO(Bool en, CTRL_PTO_S* instance, uint32_t total_pulses) {
  // 入参是否有效
  if(en == false || instance == NULL)
    return False;
  // 通道号是否正确
  if(instance->pto != 0 && instance->pto != 1) {
    instance->status = PTO_STATUS_ERR_CH_NUM;
    return false;
  }
  PWM_CONF* conf = &pwm_conf_list[instance->pto];
  // 通道是否被启用
  if(conf->is_active == 0) {
    instance->status = PTO_STATUS_ERR_NOT_ON;
    return false;
  }
  // 通道号是否为pto
  if(conf->pwm_pto != TYPE_PTO_OUTPUT) {
    instance->status = PTO_STATUS_REON;
    return false;
  }

  // 一切正常判断是否还在执行上一次作业
  if(conf->current_pulse < conf->total_pulses) {
    instance->done  = False;
    instance->error = False;
    instance->busy  = True;
  } else {
    instance->done = True;
    instance->busy = False;
  }
  if(instance->done == False) {
    return True; // 还在执行作业
  }
  if(instance->req == True) {
    conf->total_pulses = total_pulses;
    conf->pto_run_type = 1;
    conf->current_freq = instance->frequency;
    PWM_Start(instance->pto);
  }
  return True;
}
